﻿new function(jQun, Class, Enum, HTML, Event, abs, pow, sqrt, defineProperties){

this.ImageViewerActions = (function(){
	return new Enum(
		[ "Cancel", "OK", "Rotate", "VerticalFlip", "HorizontalFlip" ]
	);
}());

this.ImageViewer = (function(HTMLElementList, Canvas, CanvasImage, ImageViewerActions, PI, html, clickokbuttonEvent, document, round, getOffset){
	function ImageViewer(){
		var view = this, cx = 0, cy = 0, offset = 0, isStart = false;

		this.combine(
				html.create(null, true)
			)
			.assign({
				canvas : new Canvas(this.query("canvas")[0])
			})
			.attach({
				click : function(e, targetList){
					if(
						!targetList.isBtw("button", this)
					){
						return;
					}
					
					switch(
						targetList.getData("action") - 0
					){
						case ImageViewerActions.Cancel :
							view.remove();
							return;

						case ImageViewerActions.OK :
							targetList.dispatch(clickokbuttonEvent);
							view.remove();
							return;

						case ImageViewerActions.Rotate :
							view.degree = (view.degree + 90) % 360;
							break;

						case ImageViewerActions.VerticalFlip :
							view.flipX *= -1;
							break;

						case ImageViewerActions.HorizontalFlip :
							view.flipY *= -1;
							break;
					}

					view.refresh();
				},
				touchmove : function(e){
					if(
						!isStart
					){
						return;
					}

					// 使用touches，因为一个手指在移动时，changedTouches可能只有1个touch
					var touches = e.touches;

					e.preventDefault();

					// 单手指操作
					if(
						touches.length < 2
					){
						var touch = touches[0];

						view.refresh(
							round(view.x + (touch.clientX - cx)),
							round(view.y + (touch.clientY - cy))
						);

						// 记录当前坐标
						cx = touch.clientX;
						cy = touch.clientY;

						return;
					}
					
					// 如果是多手指操作，即缩放
					var offs = getOffset(touches);

					if(
						abs(offset - offs) < 20
					){
						return;
					}
					
					view.refresh(
						view.x,
						view.y,
						view.scale * (offset > offs ? 0.9 : 1.1)
					);

					offset = offs;
				},
				touchend : function(){
					isStart = false;
				},
				touchcancel : function(){
					isStart = false;
				}
			});
			
		this.query(
				">figure"
			)
			.attach({
				touchstart : function(e){
					var touches = e.changedTouches;

					isStart = true;

					// 如果是单手指操作
					if(
						touches.length < 2
					){
						var touch = touches[0];

						cx = touch.clientX;
						cy = touch.clientY;

						return;
					}

					offset = getOffset(touches);
				}
			});
	};
	ImageViewer = new Class(ImageViewer , "jQun.ImageViewer", HTMLElementList.prototype);

	ImageViewer.props({
		canvas : null,
		canvasHeight : 0,
		canvasWidth : 0,
		degree : 0,
		flipX : 1,
		flipY : 1,
		image : null,
		imageWidth : 0,
		imageHeight : 0,
		refresh : function(_x, _y, _scale){
			var fw, fh, fx, fy,

				canvas = this.canvas, degree = this.degree,

				flipX = this.flipX, flipY = this.flipY,

				imageWidth = this.imageWidth, imageHeight = this.imageHeight,

				canvasWidth =  this.canvasWidth, canvasHeight = this.canvasHeight,

				isHeighter = imageHeight > imageWidth && (imageHeight / imageWidth > canvasHeight / canvasWidth),
				
				sizeScale = isHeighter ? canvasHeight / imageHeight : canvasWidth / imageWidth;

			if(
				typeof _x === "undefined"
			){
				_x = this.x;
				_y = this.y;
			}

			if(
				typeof _scale === "undefined"
			){
				_scale = this.scale;
			}

			if(
				_scale < 1
			){
				_scale = 1;
			}

			fw = (isHeighter ? imageWidth * sizeScale : canvasWidth) * _scale * (degree / 90 % 2 === 1 ? canvasWidth / canvasHeight : 1);
			fh = (isHeighter ? canvasHeight : imageHeight * sizeScale) * _scale * (degree / 90 % 2 === 1 ? canvasWidth / canvasHeight : 1);
			fx = (canvasWidth - fw) / 2;
			fy = (canvasHeight - fh) / 2;
					
			if(
				isHeighter
			){
				if(
					fh < canvasHeight
				){
					fh = canvasHeight;
					fw = canvasHeight / (imageHeight / imageWidth);
				}
			}
			else {
				if(
					fw < canvasWidth
				){
					fw = canvasWidth;
					fh = canvasWidth / (imageWidth / imageHeight);
				}
			}

			switch(
				degree
			){
				case 0 :
					_x = abs(_x) > abs(fx) ? abs(fx) * (_x > 0 ? 1 : -1) : _x;
					_y = abs(_y) > abs(fy) ? abs(fy) * (_y > 0 ? 1 : -1) : _y;
					fx += _x * flipX;
					fy += _y * flipY;

					break;

				case 90 :
					fx = (canvasHeight - fw) / 2 * flipX;
					fy = (canvasWidth - fh) / 2 * flipY;
					_x = abs(_x) > abs(fy) ? abs(fy) * (_x > 0 ? 1 : -1) : _x;
					_y = abs(_y) > abs(fx) ? abs(fx) * (_y > 0 ? 1 : -1) : _y;
					fx += _y * flipX;
					fy -= (canvasWidth + _x) * flipY;

					break;

				case 180 :
					_x = abs(_x) > abs(fx) ? abs(fx) * (_x > 0 ? 1 : -1) : _x;
					_y = abs(_y) > abs(fy) ? abs(fy) * (_y > 0 ? 1 : -1) : _y;
					fx -= canvasWidth + _x;
					fy -= canvasHeight + _y;

					break;

				case 270 :
					fx = (canvasHeight - fw) / 2;
					fy = (canvasWidth - fh) / 2;
					_x = abs(_x) > abs(fy) ? abs(fy) * (_x > 0 ? 1 : -1) : _x
					_y = abs(_y) > abs(fx) ? abs(fx) * (_y > 0 ? 1 : -1) : _y;
					fx -= canvasHeight + _y;
					fy += _x;

					break;
			}
			
			canvas
				.resize(canvasWidth, canvasHeight)
				.setTransform(
					[
						"rotateZ(" + degree +"deg)",
						"scaleX(" + flipX + ")",
						"scaleY(" + flipY + ")",
						"translateX(" + (canvasWidth * (flipX === 1 ? 0 : -1)) + ")",
						"translateY(" + (canvasHeight * (flipY === 1 ? 0 : -1)) + ")"
					].join(" ")
				)
				.draw(
					this.image,
					round(fx),
					round(fy),
					round(fw),
					round(fh)
				);

			this.x = round(_x);
			this.y = round(_y);
			this.scale = _scale;

			return this;
		},
		scale : 1,
		toURL : function(_miniType, _quality, _width, _height){
			if(
				_width
			){
				return new Canvas(
						null,
						_width,
						_height
					)
					.draw(
						this.canvas,
						0,
						0,
						_width,
						_height
					)
					.toURL(
						_miniType,
						_quality
					);
			}

			return this.canvas.toURL.apply(this.canvas, arguments);
		},
		view : function(image){
			var figureList = this.query(">figure"),
			
				canvasWidth = figureList.get("offsetWidth"), canvasHeight = figureList.get("offsetHeight");

			this.image = image;

			this.imageWidth = image.naturalWidth;
			this.imageHeight = image.naturalHeight;

			this.canvasWidth = canvasWidth;
			this.canvasHeight = canvasHeight;

			this.canvas
				.resize(
					canvasWidth,
					canvasHeight
				);

			this.refresh(0, 0, 1);
			return this;
		},
		x : 0,
		y : 0
	});

	return ImageViewer.constructor;
}(
	jQun.HTMLElementList,
	jQun.Canvas,
	jQun.CanvasImage,
	this.ImageViewerActions,
	Math.PI,
	// html
	new HTML([
		'<div class="imageViewer" data-bgcolor="black">',
			'<header>',
				'@for([',
					'"' + this.ImageViewerActions.Cancel + '",',
					'"' + this.ImageViewerActions.OK + '"',
				'] ->> action){',
					'<button data-action="{action}"></button>',
				'}',
			'</header>',
			'<figure>',
				'<canvas></canvas>',
			'</figure>',
			'<footer>',
				'@for([',
					'"' + this.ImageViewerActions.Rotate + '",',
					'"' + this.ImageViewerActions.VerticalFlip + '",',
					'"' + this.ImageViewerActions.HorizontalFlip + '"',
				'] ->> action){',
					'<button data-action="{action}"></button>',
				'}',
			'</footer>',
		'</div>'
	].join("")),
	// clickokbuttonEvent
	new Event("clickokbutton"),
	document,
	Math.round,
	// getOffset
	function(touches){
		var touch1 = touches[0], touch2 = touches[1];
						
		// 根据勾股定理算偏移量
		return sqrt(
			pow(
				abs(
					touch1.clientX - touch2.clientX
				),
				2
			) + pow(
				abs(
					touch1.clientY - touch2.clientY
				),
				2
			)
		);
	}
));

this.MobileImageViewer = (function(ImageViewer){
	function MobileImageViewer(image, _parentNode){
		// 以后肯定要将ImageViewer分离的
	};
	MobileImageViewer = new Class(MobileImageViewer, "jQun.MobileImageViewer", ImageViewer.prototype);

	return MobileImageViewer.constructor;
}(
	this.ImageViewer
));

defineProperties(jQun, this);
}(
	jQun,
	jQun.Class,
	jQun.Enum,
	jQun.HTML,
	jQun.Event,
	Math.abs,
	Math.pow,
	Math.sqrt,
	jQun.defineProperties
);